package com.ayou.builder;

import cn.hutool.core.util.ClassUtil;
import com.ayou.annotations.Delete;
import com.ayou.annotations.Insert;
import com.ayou.annotations.Select;
import com.ayou.annotations.Update;
import com.ayou.mapping.MappedStatement;
import com.ayou.mapping.SqlCommandType;
import com.ayou.session.Configuration;
import com.google.common.collect.Lists;
import lombok.SneakyThrows;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Set;

/**
 * @description:  Xml解析
 * @author: ayouman
 * @date: 2024/7/1 22:17
 */
public class XmlConfigBuilder {
    ArrayList<Class<? extends Annotation>> sqlAnnotations = Lists.newArrayList(Select.class, Insert.class, Update.class, Delete.class);
    public Configuration parse() {
        Configuration configuration = new Configuration();
        paeseMapper(configuration);
        return configuration;
    }

    @SneakyThrows
    private void paeseMapper(Configuration configuration) {
        // 示例包 com.demo.mapper
        Set<Class<?>> classes = ClassUtil.scanPackage("com.demo.mapper");
        for (Class<?> aClass : classes) {
            Method[] methods = aClass.getMethods();
            for (Method method : methods) {
                SqlCommandType sqlCommandType = null;
                String originalSql = "";
                for (Class<? extends Annotation> sqlAnnotation : sqlAnnotations) {
                    Annotation annotation = method.getAnnotation(sqlAnnotation);
                    if (annotation != null) {
                        originalSql = (String) annotation.getClass().getMethod("value").invoke(annotation);
                        if (annotation instanceof Select) {
                            sqlCommandType = SqlCommandType.SELECT;
                            break;
                        } else if (annotation instanceof Insert) {
                            sqlCommandType = SqlCommandType.INSERT;
                            break;
                        } else if (annotation instanceof Update) {
                            sqlCommandType = SqlCommandType.UPDATE;
                            break;
                        } else if (annotation instanceof Delete) {
                            sqlCommandType = SqlCommandType.DELETE;
                            break;
                        }
                    }
                }

                Class returnClass = method.getReturnType();
                Type returnType = method.getGenericReturnType();
                Boolean selectMany = returnType instanceof ParameterizedType;
                if (selectMany) {
                    returnClass = (Class) ((ParameterizedType) returnType).getActualTypeArguments()[0];
                }

                MappedStatement build = MappedStatement.builder()
                        .id(aClass.getName() + "." + method.getName())
                        .sql(originalSql)
                        .resultType(returnClass)
                        .sqlCommandType(sqlCommandType)
                        .selectMany(selectMany)
                        .build();

                configuration.addMappedStatement(build);
            }
        }
    }

}
